using AutoMapper;
using UwinEducation.Application.Common.Interfaces;
using UwinEducation.Application.Dtos;
using UwinEducation.Domain.Entities;
using UwinEducation.Domain.IRepositories;
using UwinEducation.Infrastructure.Persistence;
using UwinEducation.Infrastructure.Repositories;
using UwinEducation.Shared.Enums;
using UwinEducation.Shared.Exceptions;
using UwinEducation.Shared.Models;

namespace UwinEducation.Application.Services
{
    /// <summary>
    /// 学生课表服务实现
    /// </summary>
    public class StudentScheduleService : IStudentScheduleService
    {

        private readonly IStudentScheduleRepository _studentScheduleRepository;
        private readonly IStudentPaymentRepository _studentPaymentRepository;

        private readonly IStudentPaymentService _studentPaymentService;
        private readonly ITeacherScheduleRepository _teacherScheduleRepository;
        private readonly ITeacherScheduleDetailsRepository _teacherScheduleDetailsRepository;
        private readonly IStudentRepository _studentRepository;
        private readonly IMapper _mapper;
        private readonly ApplicationDbContext _context;

        public StudentScheduleService(
            IStudentScheduleRepository studentScheduleRepository,
            IStudentPaymentRepository studentPaymentRepository,
            IStudentPaymentService studentPaymentService,
            ITeacherScheduleRepository teacherScheduleRepository,
            ITeacherScheduleDetailsRepository teacherScheduleDetailsRepository,
            IStudentRepository studentRepository,
            IMapper mapper,
            ApplicationDbContext context
        )
        {
            _studentScheduleRepository = studentScheduleRepository;
            _studentPaymentRepository = studentPaymentRepository;
            _studentPaymentService = studentPaymentService;
            _teacherScheduleRepository = teacherScheduleRepository;
            _teacherScheduleDetailsRepository = teacherScheduleDetailsRepository;
            _studentRepository = studentRepository;
            _mapper = mapper;
            _context = context;
        }

        /// <summary>
        /// 获取学生课表分页列表
        /// </summary>
        public async Task<PagedResult<StudentScheduleDto>> GetPagedListAsync(
            StudentSchedulePageRequest pageRequest
        )
        {
            var result = await _studentScheduleRepository.GetPagedListAsync(pageRequest);
            return new PagedResult<StudentScheduleDto>
            {
                Total = result.Total,
                Items = _mapper.Map<List<StudentScheduleDto>>(result.Items),
            };
        }

        

        public async Task<PagedResult<StudentScheduleStatisticsDto>> GetStatisticsPagedListAsync(
            StudentScheduleStatisticsPageRequest pageRequest
        )
        {
            var result = await _studentScheduleRepository.GetStatisticsPagedListAsync(pageRequest);

            var details= await _studentScheduleRepository.GetByStudentIdAsync(pageRequest.StudentId);

            //根据StudentIds和TeacherScheduleIds批量查询缴费
            var studentPayments = await _studentPaymentRepository.GetPagedListAsync(
                new StudentPaymentPageRequest
                {
                    PageIndex = 1,
                    PageSize = 999,
                    StudentId = pageRequest.StudentId,
                }
            );

            //将result.Items转换为StudentScheduleStatisticsDto
            var statistics = result
                .Items.Where(item=>item.studentSchedule.TeacherSchedule!=null).Select(item => new StudentScheduleStatisticsDto
                {
                    TeacherScheduleId = item.studentSchedule.TeacherScheduleId,
                    StudentId = item.studentSchedule.StudentId,
                    TeacherName = item.studentSchedule.TeacherSchedule.Teacher.Name,
                    CourseName = item.studentSchedule.TeacherSchedule.Course.Name,
                    CoursePrice = item.studentSchedule.TeacherSchedule.UnitPrice,
                    CourseCount = item.courseCount,
                    CourseTotalPrice = item.courseCount * item.studentSchedule.TeacherSchedule.UnitPrice,
                    PaidAmount = studentPayments
                        .Items.Where(x =>
                            x.StudentId == item.studentSchedule.StudentId
                            && x.TeacherScheduleGroupId == item.studentSchedule.TeacherScheduleId
                        )
                        .FirstOrDefault()
                        ?.PaidAmount ?? 0,
                    TeacherScheduleDetails = details.Where(x => x.TeacherScheduleId == item.studentSchedule.TeacherScheduleId).Select(x => _mapper.Map<TeacherScheduleDetailsDto>(x.TeacherScheduleDetails)).ToList()
                })
                .ToList();

            //CoursePrice*CourseCount-PaidAmount=UnpaidAmount
            if(pageRequest.PaymentStatus.HasValue)
            {
                if(pageRequest.PaymentStatus.Value==PaymentStatus.Paid)
                {
                    //返回已缴费的课表
                    statistics = statistics.Where(x => x.PaidAmount >= x.CoursePrice * x.CourseCount).ToList();
                }
                else if(pageRequest.PaymentStatus.Value==PaymentStatus.PartiallyPaid)
                {
                    //返回未缴费的课表
                    statistics = statistics.Where(x => x.PaidAmount < x.CoursePrice * x.CourseCount).ToList();
                }
            }
            return new PagedResult<StudentScheduleStatisticsDto>
            {
                Total = result.Total,
                Items = statistics,
            };
        }

        /// <summary>
        /// 获取学生课表详情
        /// </summary>
        public async Task<StudentScheduleDto> GetByIdAsync(Guid id)
        {
            var schedule = await _studentScheduleRepository.GetDetailsByIdAsync(id);
            if (schedule == null)
            {
                throw new ArgumentException($"学生课表不存在: {id}");
            }

            return _mapper.Map<StudentScheduleDto>(schedule);
        }

        /// <summary>
        /// 创建学生课表
        /// </summary>
        public async Task<StudentScheduleDto> CreateAsync(CreateStudentScheduleDto input)
        {
            // 验证学生是否存在
            await ValidateStudentExistenceAsync(input.StudentId);

            //验证课表是否存在
            var studentSchedule = await _studentScheduleRepository.GetByTeacherScheduleIdAsync(
                input.TeacherScheduleId,
                input.StudentId
            );
            if (studentSchedule != null)
            {
                throw new ArgumentException($"学生课表已存在: {input.TeacherScheduleId}");
            }

            // 验证教师课表是否存在和容量是否足够
            var teacherSchedule = await _teacherScheduleDetailsRepository.GetByIdAsync(
                input.TeacherScheduleId
            );
            if (teacherSchedule == null)
            {
                throw new ArgumentException($"教师课表不存在: {input.TeacherScheduleId}");
            }

            var usedCapacity =
                await _studentScheduleRepository.GetUsedCapacityByTeacherScheduleGroupIdAsync(
                    input.TeacherScheduleGroupId
                );
            if (usedCapacity >= teacherSchedule.TeacherSchedule.Capacity)
            {
                throw new ArgumentException($"教师课表容量不足: {input.TeacherScheduleId}");
            }

            var schedule = StudentSchedule.Create(
                input.StudentId,
                input.TeacherScheduleId,
                input.TeacherScheduleGroupId,
                input.IsForceCheck,
                input.Reason,
                input.Remarks
            );
            await _studentScheduleRepository.AddAsync(schedule);
            return _mapper.Map<StudentScheduleDto>(schedule);
        }

        /// <summary>
        /// 批量创建学生课表
        /// </summary>
        public async Task<List<StudentScheduleDto>> CreateRangeAsync(
            CreateStudentScheduleRangeDto inputs
        )
        {
            List<string> businessExceptions = new List<string>();

            //学生是否存在
            await ValidateStudentExistenceAsync(inputs.StudentId);

            // 验证教师课表是否存在和容量是否足够
            await ValidateTeacherScheduleCapacityAsync(inputs);

            //批量验证课表是否存在
            List<StudentSchedule> studentSchedules = await ValidateStudentSchedulesExistenceAsync(
                inputs
            );

            //批量验证教师课表是否废弃
            await ValidateTeacherScheduleIsInvalidAsync(inputs);

            //学生课表时间是否冲突
            await ValidateStudentScheduleTimeConflictAsync(inputs, businessExceptions);

            if (inputs.IsForceCheck)
            {
                if (businessExceptions != null && businessExceptions.Count > 0)
                {
                    throw new BusinessException(businessExceptions, "StudentSchedule");
                }
            }

            //批量创建学生课表
            studentSchedules = inputs
                .StudentSchedules.Select(x =>
                    StudentSchedule.Create(
                        inputs.StudentId,
                        x.TeacherScheduleId,
                        inputs.TeacherScheduleGroupId,
                        inputs.IsForceCheck,
                        x.Reason ?? string.Empty,
                        x.Remarks ?? string.Empty
                    )
                )
                .ToList();

            using (var transaction = await _context.Database.BeginTransactionAsync())
            {
                try
                {
                    await _studentScheduleRepository.AddRangeAsync(studentSchedules);
                    //批量创建学生缴费_studentPaymentService.CreateRangeAsync
                    List<CreateStudentPaymentDto> studentPayments = new List<CreateStudentPaymentDto>();
                    foreach (var schedule in studentSchedules)
                    {
                        studentPayments.Add(new CreateStudentPaymentDto
                        {
                            StudentId = inputs.StudentId,
                            TeacherScheduleGroupId = inputs.TeacherScheduleGroupId,
                            Amount = 0,
                            TotalAmount = 0
                        });
                    }
                    
                    await _studentPaymentService.CreateRangeAsync(studentPayments);

                    // var studentPayments = studentSchedules.Select(x => StudentPayment.Create(
                    //     inputs.StudentId,
                    //     inputs.TeacherScheduleGroupId,
                    //     0,
                    //     0
                    // )).ToList();
                    //await _studentPaymentService.CreateRangeAsync(studentPayments);
                    await transaction.CommitAsync();
                }
                catch (Exception ex)
                {
                    await transaction.RollbackAsync();
                    throw new Exception("批量创建学生课表失败", ex);
                }
            }
            return _mapper.Map<List<StudentScheduleDto>>(studentSchedules);

            //await _studentScheduleRepository.AddRangeAsync(studentSchedules);
            ////批量创建学生缴费
            //var studentPayments = studentSchedules.Select(x => StudentPayment.Create(
            //    inputs.StudentId,
            //    inputs.TeacherScheduleGroupId,
            //    0,
            //    0
            //)).ToList();
            //await _studentPaymentRepository.AddRangeAsync(studentPayments);


            //return _mapper.Map<List<StudentScheduleDto>>(studentSchedules);
        }

        /// <summary>
        /// 验证教师课表是否废弃
        /// </summary>
        private async Task ValidateTeacherScheduleIsInvalidAsync(CreateStudentScheduleRangeDto inputs)
        {
            var teacherSchedules = await _teacherScheduleRepository.GetByGroupIdAsync(inputs.TeacherScheduleGroupId);
            //提示具体哪一天的课表已废弃   
            var abandonedTeacherScheduleDetails = teacherSchedules.SelectMany(x => x.TeacherScheduleDetails).Where(y => y.Status == ScheduleStatus.Abandoned).ToList();
            if (abandonedTeacherScheduleDetails.Count > 0)
            {
                throw new ArgumentException($"教师课表已废弃: {abandonedTeacherScheduleDetails.Select(x => x.StartTime.ToString("yyyy-MM-dd")).Aggregate((x, y) => $"{x}, {y}")}");
            }
        
        }

        /// <summary>
        /// 验证学生课表时间冲突
        /// </summary>
        private async Task ValidateStudentScheduleTimeConflictAsync(
            CreateStudentScheduleRangeDto inputs,
            List<string> businessExceptions
        )
        {
            //根据IDS批量查询 TeacherScheduleDetails
            var teacherSchedulesDetails = await _teacherScheduleDetailsRepository.GetByIdsAsync(
                inputs.StudentSchedules.Select(x => x.TeacherScheduleId).ToList()
            );
            if (teacherSchedulesDetails == null|| teacherSchedulesDetails.Count==0)
                return;
            //根据teacherSchedulesDetails，算出最早的开始时间和最晚的结束时间

            var startTime = teacherSchedulesDetails.Min(x => x.StartTime);
            var endTime = teacherSchedulesDetails.Max(x => x.EndTime);

            //获取学生所有现有课表
            var studentSchedules = await _studentScheduleRepository.GetByStudentIdAsync(
                inputs.StudentId,
                startTime,
                endTime
            );


            // 时间段冲突的条件：
            // 1. 新开始时间在现有时间段内
            // 2. 新结束时间在现有时间段内
            // 3. 新时间段完全包含现有时间段
            foreach (var schedule in studentSchedules)
            {
                var hasConflict = teacherSchedulesDetails
                .Where(x => x.Status == ScheduleStatus.Normal)
                .Any(x =>
                    (schedule.TeacherScheduleDetails.StartTime >= x.StartTime && schedule.TeacherScheduleDetails.StartTime <= x.EndTime) ||
                    (schedule.TeacherScheduleDetails.EndTime >= x.StartTime && schedule.TeacherScheduleDetails.EndTime <= x.EndTime) ||
                    (schedule.TeacherScheduleDetails.StartTime < x.StartTime && schedule.TeacherScheduleDetails.EndTime > x.EndTime)
                );
                if (hasConflict)
                {
                    businessExceptions.Add(
                        $"时间冲突: {schedule.TeacherScheduleDetails.StartTime:yyyy-MM-dd HH:mm} - {schedule.TeacherScheduleDetails.EndTime:yyyy-MM-dd HH:mm} 与 {schedule.TeacherSchedule.Course.Name} 时间重叠"
                    );
                }
            }



            // foreach (var schedule in studentSchedules)
            // {
            //     var hasConflict = teacherSchedulesDetails.Any(x =>
            //         x.StartTime >= schedule.TeacherScheduleDetails.StartTime
            //         && x.EndTime <= schedule.TeacherScheduleDetails.EndTime
            //     );
            //     if (hasConflict)
            //     {
            //         businessExceptions.Add(
            //             $"时间冲突: {schedule.TeacherScheduleDetails.StartTime:yyyy-MM-dd HH:mm} - {schedule.TeacherScheduleDetails.EndTime:yyyy-MM-dd HH:mm} 与 {schedule.TeacherSchedule.Course.Name} 时间重叠"
            //         );
            //     }
            // }
        }

        private async Task<List<StudentSchedule>> ValidateStudentSchedulesExistenceAsync(
            CreateStudentScheduleRangeDto inputs
        )
        {
            var studentSchedules = await _studentScheduleRepository.GetByTeacherScheduleIdsAsync(
                inputs.StudentSchedules.Select(x => x.TeacherScheduleId).ToList(),
                inputs.StudentId
            );
            if (studentSchedules.Count > 0)
            {
                throw new ArgumentException(
                    $"学生课表已存在: {inputs.StudentSchedules.First().TeacherScheduleId}"
                );
            }

            return studentSchedules;
        }

        private async Task ValidateTeacherScheduleCapacityAsync(
            CreateStudentScheduleRangeDto inputs
        )
        {
            var teacherSchedule = await _teacherScheduleRepository.GetByIdAsync(
                inputs.StudentSchedules.First().TeacherScheduleId
            );
            //教师课表组容量是否足够
            var usedCapacity =
                await _studentScheduleRepository.GetUsedCapacityByTeacherScheduleGroupIdAsync(
                    inputs.TeacherScheduleGroupId
                );

            if (teacherSchedule != null && usedCapacity >= teacherSchedule.Capacity)
            {
                throw new ArgumentException($"教师课表组容量不足: {inputs.TeacherScheduleGroupId}");
            }
        }

        private async Task ValidateStudentExistenceAsync(Guid studentId)
        {
            var student = await _studentRepository.GetByIdAsync(studentId);
            if (student == null)
            {
                throw new ArgumentException($"学生不存在: {studentId}");
            }
        }

        /// <summary>
        /// 更新学生课表
        /// </summary>
        public async Task<StudentScheduleDto> UpdateAsync(UpdateStudentScheduleDto input)
        {
            var schedule = await _studentScheduleRepository.GetByIdAsync(input.Id);
            if (schedule == null)
            {
                throw new ArgumentException($"学生课表不存在: {input.Id}");
            }

            schedule.Status = input.Status??ScheduleStatus.Normal;
            schedule.Reason = input.Reason??string.Empty;
            schedule.Remarks = input.Remarks??string.Empty;

            await _studentScheduleRepository.UpdateAsync(schedule);
            return _mapper.Map<StudentScheduleDto>(schedule);
        }

        /// <summary>
        /// 删除学生课表
        /// </summary>
        public async Task DeleteAsync(Guid id)
        {
            var schedule = await _studentScheduleRepository.GetByIdAsync(id);
            if (schedule == null)
            {
                throw new ArgumentException($"学生课表不存在: {id}");
            }
            await _studentScheduleRepository.DeleteAsync(id);

            //根据Guid studentId, Guid teacherScheduleId查询学生课表是否存在
            var studentSchedules = await _studentScheduleRepository.GetByStudentIdAndTeacherScheduleIdAsync(schedule.StudentId, schedule.TeacherScheduleId);
            if(studentSchedules.Count==0)
            {
                await _studentPaymentService.DeleteByStudentIdAndTeacherScheduleIdAsync(schedule.StudentId, schedule.TeacherScheduleId);
            }
        }

        //根据学生ID和教师课表ID删除学生课表
        public async Task DeleteByStudentIdAndTeacherScheduleIdAsync(Guid studentId, Guid teacherScheduleId)
        {
            await _studentScheduleRepository.DeleteByStudentIdAndTeacherScheduleIdAsync(studentId, teacherScheduleId);
            await _studentPaymentService.DeleteByStudentIdAndTeacherScheduleIdAsync(studentId, teacherScheduleId);
        }

        /// <summary>
        /// 获取学生的所有课表
        /// </summary>
        public async Task<List<StudentScheduleDto>> GetByStudentIdAsync(Guid studentId)
        {
            var schedules = await _studentScheduleRepository.GetByStudentIdAsync(studentId);
            return _mapper.Map<List<StudentScheduleDto>>(schedules);
        }

        /// <summary>
        /// 获取指定日期范围内的学生课表
        /// </summary>
        public async Task<List<StudentScheduleDto>> GetByDateRangeAsync(
            Guid studentId,
            DateTime startDate,
            DateTime endDate
        )
        {
            var schedules = await _studentScheduleRepository.GetByDateRangeAsync(
                studentId,
                startDate,
                endDate
            );
            return _mapper.Map<List<StudentScheduleDto>>(schedules);
        }

        /// <summary>
        /// 获取教师课表列表
        /// </summary>
        public async Task<List<TeacherScheduleListDto>> GetTeacherScheduleListAsync(TeacherScheduleListRequest request)
        {
            var dtos = new List<TeacherScheduleListDto>();

            var schedules = await _studentScheduleRepository.GetByTeacherIdAndDateRangeAsync(request.TeacherId,request.StartDate,request.EndDate);


            //根据schedules，统计相同TeacherScheduleDetailsId的课表和学生列表
            var teacherScheduleDetailsList = schedules
                .GroupBy(x => x.TeacherScheduleDetailsId)
                .Select(x => new
                {
                    id = x.Key,
                    startTime = x.First().TeacherScheduleDetails.StartTime,
                    endTime = x.First().TeacherScheduleDetails.EndTime,
                    Course = x.First().TeacherSchedule.Course,
                    Classroom = x.First().TeacherSchedule.Classroom,
                    Students = x.Select(y => y.Student).ToList(),
                    Status = x.First().TeacherScheduleDetails.Status,
                    Reason = x.First().TeacherScheduleDetails.Reason,
                    Remarks = x.First().TeacherScheduleDetails.Remarks
                })
                .ToList();

            

            
            foreach (var schedule in teacherScheduleDetailsList)
            {
                dtos.Add(new TeacherScheduleListDto
                {
                    StartTime = schedule.startTime,
                    EndTime = schedule.endTime,
                    Status = schedule.Status,
                    Reason = schedule.Reason,
                    Remarks = schedule.Remarks,
                    Course = _mapper.Map<CourseDto>(schedule.Course),
                    Classroom = _mapper.Map<ClassroomDto>(schedule.Classroom),
                    Students = schedule.Students.Select(x => _mapper.Map<StudentDto>(x)).ToList()
                    
                });
            }
            return dtos;
        }

        /// <summary>
        /// 获取学生课表列表
        /// </summary>
        public async Task<List<StudentScheduleListDto>> GetStudentScheduleListAsync(StudentScheduleListRequest request)
        {
            var schedules = await _studentScheduleRepository.GetByDateRangeAsync(request.StudentId,request.TeacherScheduleId, request.StartDate,request.EndDate);
            if(request.TeacherScheduleId.HasValue)
                schedules = schedules.Where(x => x.TeacherScheduleId == request.TeacherScheduleId.Value).ToList();

            return _mapper.Map<List<StudentScheduleListDto>>(schedules);
        }

        /// <summary>
        /// 获取教师课表下的所有学生（去重）
        /// </summary>
        /// <param name="teacherScheduleId">教师课表ID</param>
        /// <returns>学生列表</returns>
        public async Task<List<StudentDto>> GetDistinctStudentsByTeacherScheduleIdAsync(Guid teacherScheduleId)
        {
            var students = await _studentScheduleRepository.GetDistinctStudentsByTeacherScheduleIdAsync(teacherScheduleId);
            return _mapper.Map<List<StudentDto>>(students);
        }
    }
}

